import { history } from 'umi';
import eventBus from '@/utils/eventBus';

/**
 *  原理:1、左侧菜单的path作为右侧tabs的唯一key
 *       2、包裹tabPanel中的content的，使用getDerivedState来保证切换后不刷新
 *       3、刷新功能通过cloneElement并附加一个变化的count属性来实现
 *
 *  history储存对应tabs下的路由历史
 *  historyIndex对应tabs下的当前路由历史索引
 *  currentKey用于保证左侧菜单的选中状态和tabs的选中状态一致
 *  openSwitch用于标记接下来的跳转是打开/或者切换tabs
 *  refresh用于标记接下来的跳转是tab内刷新
 *  historyRoute用于标记接下来的跳转不引起路由历史变化
 *  goInitHistory用于标记接下来的跳转要切换到某个路由历史的顶部
 *  defaultOpenTabKey用于配置特定路由，当处于这个路由时（currentKey），跳转均打开新的tab
 *  multipleOpenTabKey用于配置特定路由，当访问这个路由时，建query放入tabKey中，实现同一个路由打开多个页签
 *  configOpenTabKey用于配置某些特定路由，直接访问该路由时，tabKey不遵从路由文件，而是配置中固定的
 *  routerAction用以记录当前的跳转类型
 *  needRenderFirstTab用以标记时否需要渲染第一个页签，用以完成固定第一个页签的功能
 *  ChildrenTabs组件中同步过来tabs的state
 *
 *  跨选项卡刷新方案:
 *  1. 简单场景: 详情页保存完关闭后跳转列表页并刷新
 *  history.push({ pathname: '...', state: { tabRoute: true, tabRefresh: true, closeTab: true } });
 *  2. 复杂场景: 数据更新后, 多个页面或者其他页面的某个模块要刷新
 *  列表页:
 *  useEffect(() => {
        pageTabUtil.sub('refreshList', run);
        return () => {
            pageTabUtil.unSub('refreshList')
        }
    }, [run]);
 * 详情页:
 * pageTabUtil.pub('refreshList');
 */
const util = {
    history: {},
    historyIndex: {},
    currentKey: null,
    openSwitch: false,
    refresh: false,
    historyRoute: false,
    goInitHistory: null,
    defaultOpenTabKey: ['/personal/portal'],
    configOpenTabKey: {
        '/office/personnelManagement/organization/rank/detail': '/office/institutions/rulesManage/personnel'
    },
    // 使用query
    needMultiple: true,
    // 使用model数据源的页面，暂时强制刷新以避免问题
    forceRefreshPathList: [
        '/personal/portal/myApplication/detail', // 申请详情
        '/personal/portal/notice/noticeDetail', // 公告详情
        '/personal/portal/waitApproval/approvalDetail', // 审批详情
        '/office/institutions/rulesManage/institutionsDetail', // 制度详情
        '/office/personnelManagement/organization/rank/detail', // 职级详情
        '/personal/portal/myAuditRead/myAuditReadDetail', // 我的审批详情
        '/office/info/notice/noticeDetail', // 公告管理详情
        '/office/personnelManagement/attendance/timetag/attendRecord/clockRecord' // 打卡记录
        // '/personal/portal/apply' // 发起审批
    ],
    // 强制不使用query作为页签key
    forceDisableMultiple: ['/personal/portal/apply', '/office/personnelManagement/recruitment/interview/record'],
    routerAction: null,
    needRenderFirstTab: false,
    tabsState: [],
    eventMap: {
        REFRESH_TAB: 'refreshTab',
        REMOVE_TAB: 'removeTab',
        CHANGE_TAB: 'changeTab',
        ADD_TAB: 'addTab',
        AFTER_MOVE_TAB: 'afterRemoveTab'
    },
    // 判断并更新tab的打开/切换标记
    isOpenSwitch(consume = true) {
        const flag = this.openSwitch;
        if (consume) this.openSwitch = false;
        return flag;
    },
    // 设置tab的打开/切换标记
    // config.location 路由
    // config.tabKey 已存在的tabKey
    setOpenSwitch(config) {
        this.setCurrentKey(config);
        this.openSwitch = true;
    },
    // 判断并更新tab的刷新标记
    isRefresh() {
        const flag = this.refresh;
        this.refresh = false;
        return flag;
    },
    // 设置tab的刷新标记
    setRefresh() {
        this.refresh = true;
    },
    // 设置某个tab下的路由历史
    setTabHistory({ tabKey, route = {} }) {
        if (this.historyRoute) {
            this.historyRoute = false;
            return;
        }

        // 重置掉初始化标记
        this.goInitHistory = null;

        // 如果是history.replace
        if (this.getRouterAction() === 'REPLACE' && this.history[tabKey]) {
            this.history[tabKey] = [...this.history[tabKey].slice(0, this.historyIndex[tabKey]), route];
            return;
        }

        // 初始化
        if (!this.history[tabKey] || !this.history[tabKey].length) {
            const { pathname = tabKey, query = {} } = route;
            this.history[tabKey] = [{ pathname, query }];
            this.historyIndex[tabKey] = 0;
            return;
        }

        // 推入新的路由到队列
        const currentRoute = this.getTabRoute(tabKey);
        // 排除重复的，某些页面需要去排查一下
        if (currentRoute?.pathname === route?.pathname && this.generateKey(currentRoute) === this.generateKey(route)) {
            return;
        }

        const nextIndex = this.historyIndex[tabKey] + 1;
        this.history[tabKey] = [...this.history[tabKey].slice(0, nextIndex), route];
        this.historyIndex[tabKey] = nextIndex;
    },
    // 清除某个tab下的路由历史
    clearTabHistory(tabKey) {
        this.history[tabKey] = [];
        this.historyIndex[tabKey] = 0;
    },
    clearAllTabHistory() {
        this.currentKey = null;
        this.history = {};
        this.historyIndex = {};
    },
    // 获取某个tab下的路由可操作状态
    getTabHistoryStatus(tabKey, forward = 0) {
        if (!this.history[tabKey]) return false;

        const len = this.history[tabKey].length;
        const index = this.historyIndex[tabKey];
        if (index + forward > len - 1 || index + forward < 0) return false;
        return true;
    },
    // 获取路由信息
    getTabHistory(tabKey, forward = 0) {
        const index = this.historyIndex[tabKey];
        this.historyIndex[tabKey] = index + forward;
        return this.history[tabKey][index + forward];
    },
    // 跳转到某个tab下历史路由
    goTabHistory(tabKey, forward = 0) {
        if (!this.history[tabKey] || !this.history[tabKey].length) return;
        if (!this.getTabHistoryStatus(tabKey, forward)) {
            this.closeTab(null, {
                callback: () => {
                    this.refreshTab();
                }
            });
            return;
        }
        const index = this.historyIndex[tabKey];
        this.historyIndex[tabKey] = index + forward;
        const route = this.history[tabKey][index + forward];
        this.historyRoute = true;
        history.push(route);
    },
    // 返回当前tab的上一个路由
    goBack(forward = -1) {
        this.goTabHistory(this.currentKey, forward);
    },

    // 设置跳转到某个tab下历史首个路由的标记
    setInitHistory() {
        this.goInitHistory = this.currentKey;
    },
    // 获取跳转到某个tab下历史首个路由的标记
    isInitHistory(tabKey) {
        // 排除点击顶部tab的情况，需要更合理的方式
        if (this.goInitHistory === tabKey) {
            this.goInitHistory = null;
            return true;
        }
        this.goInitHistory = null;
        return false;
    },
    // 保存当前tab的tabKey
    setCurrentKey({ location, tabKey }) {
        if (!this.isNeedMultiple() || this.forceDisableMultiple.some(path => location?.pathname === path)) {
            this.currentKey = tabKey ?? location?.pathname;
            return;
        }
        if (tabKey) {
            console.log('currentKey', tabKey);
            this.currentKey = tabKey;
        } else if (location) {
            this.currentKey = this.generateKey(location);
        }
    },
    // 获取当前tab的tabKey
    getCurrentKey() {
        return this.currentKey;
    },
    // 获取当前tab的pathname
    getCurrentPath() {
        return this.currentKey?.split('?')[0];
    },
    // 重置某个tab
    resetHistory(tabKey, route = {}) {
        this.clearTabHistory(tabKey);
        const { state, ...rest } = route; // state是一次性的
        this.setTabHistory({ tabKey, route: rest });
    },
    // 获取不同的tabs下当前路由
    getTabRoute(tabKey, toIndex) {
        if (!this.history[tabKey]) return null;
        const index = toIndex || this.historyIndex[tabKey];
        return this.history[tabKey][index];
    },
    // 封装打开tab的方法, refresh进行刷新
    openTab(pathname, query, option = { refresh: true }) {
        this.setOpenSwitch({
            location: { pathname, query }
        });
        if (option.refresh) this.setInitHistory();
    },
    // 特殊：判断配置页面（个人主页）都以tabs方式打开
    handleDefaultOpenTabKey(pathname, query) {
        if (this.defaultOpenTabKey.includes(this.currentKey) && pathname !== this.currentKey) {
            this.openTab(pathname, query);
        }
    },
    // 特殊：处理浏览器路由前进后退时到达配置路由时（个人主页），直接切换而不是在当前tab内刷新
    handleHistoryOpenTabKey(path, action) {
        if (this.defaultOpenTabKey.includes(path) && action === 'POP') {
            this.openTab(path);
        }
    },
    // 判断该页面以哪一个tabKey打开
    handleConfigOpenTabKey(path) {
        const tabKey = this.configOpenTabKey[path];
        if (tabKey) {
            this.openTab(tabKey);
        }
    },
    // 设置当前跳转类型
    setRouterAction(action) {
        this.routerAction = action;
    },
    // 获取当前跳转类型
    getRouterAction() {
        return this.routerAction;
    },
    // 关闭页签
    closeTab(tabKey, option = {}) {
        const { callback, autoRedirect = true } = option;
        this.pub(this.eventMap.REMOVE_TAB, { key: tabKey || this.currentKey, autoRedirect });
        if (callback) {
            setTimeout(() => {
                callback();
            });
        }
    },
    // 刷新并跳转
    refreshTab(tabKey) {
        this.pub(this.eventMap.REFRESH_TAB, tabKey || this.currentKey);
    },
    setTabsState(state) {
        this.tabsState = state;
    },
    getTabState() {
        return this.tabsState;
    },
    pub(event, value) {
        eventBus.emit(event, value);
    },
    sub(event, callback) {
        eventBus.addListener(event, value => {
            callback(value);
        });
    },
    unSub(event, callback) {
        eventBus.removeListener(event, callback);
    },
    generateKey(location = {}) {
        const { pathname, query = {} } = location;
        const queryKeys = Object.keys(query).sort(); // 保证顺序
        if (queryKeys.length && !pathname.includes('?')) {
            return `${pathname}?${queryKeys
                .filter(item => query[item] !== undefined) //  router会自动过滤掉undefined，保持一致
                .map(item => `${item}=${query[item]}`)
                .join('&')}`;
        }
        return pathname;
    },
    // 是否使用query生成tabKey，从而支持相同路由存在多个页签
    isNeedMultiple() {
        return this.needMultiple;
    },
    // 通过路由监听来添加的路由处理
    onBeforeRouteChange({ pathname, action, state, query }) {
        // 通过添加参数的形式实现: 关闭当前页面刷新目标页面并跳转
        // history.push({ pathname: '...', state: { tabRoute: true, tabRefresh: true, closeTab: true } });
        if (state?.closeTab) {
            this.closeTab(this.currentKey, { autoRedirect: false });
        }
        this.setRouterAction(action);
        // 初次进入应用时，需要设置
        if (!this.currentKey) {
            this.setCurrentKey({
                location: { pathname, query }
            });
        }
        if (state?.tabRoute) {
            this.openTab(pathname, query, { refresh: state.tabRefresh });
        }
        this.handleDefaultOpenTabKey(pathname, query);
        this.handleHistoryOpenTabKey(pathname, action);
    },
    // 点击页签切换时
    // config.location 路由
    // config.tabKey 已存在的tabKey
    onTabChange({ location = {}, tabKey }) {
        const { pathname, query } = location;
        const needForceRefresh = this.forceRefreshPathList.some(path => pathname === path);

        const extra = {};
        if (needForceRefresh) {
            extra.state = { tabRoute: true, tabRefresh: true };
        } else {
            // 切换tab时无法用当前的location生成初始的tabKey
            this.setOpenSwitch({ tabKey });
            // 禁用掉路由的页签操作，改为上面的util内部实现，这部分需要优化一下?
            extra.state = { tabRoute: false, tabRefresh: false };
        }

        history.push({
            pathname,
            query,
            ...extra
        });
    }
};

export default util;
